assume cs:code, ds:data

data segment
original_9 dw 0, 0 ;原始的9号中断(也就是bios提供的9号中断)的入口地址,前面为ip，后面为cs
data ends


code segment
start:			;保存原来的9号中断的入口地址
				mov ax, 0
				mov es, ax
				mov ax, data
				mov ds, ax
				mov ax, es:[4 * 9]
				mov original_9[0], ax
				mov ax, es:[4 * 9 + 2]
				mov original_9[2], ax

				;设置新的9号中断
				cli ;设置标志寄存器的IF位为0
				mov word ptr es:[4 * 9], offset my_int9
				mov es:[4 * 9 + 2], cs
				sti	;设置标志寄存器的IF位为1
				
				;在屏幕上面依次显示a到z
				mov ax, 0b800h
				mov es, ax
				mov al, 'a'
show_single:	mov es:[160 * 12 + 40 * 2], al
				;mov byte ptr es:[160 * 12 + 40 * 2 + 1], 42h
				call delay ;调用延迟子程序，延迟一段时间,免得切换地太快，根本看不到效果
				inc al
				cmp al, 'a'
				jb quit_my
				cmp al, 'z'
				ja quit_my
				jmp short show_single

				;恢复原来的9号中断
quit_my:		mov ax, 0
				mov es, ax
				mov ax, original_9[0]
				mov es:[4 * 9], ax
				mov ax, original_9[2]
				mov es:[4 * 9 + 2], ax

				mov ax, 4c00h
				int 21h



;延迟子程序，故意对一个很大的数执行循环减，直到减为0为止。ax为低位，dx为高位
delay:			push ax
				push dx

				mov ax, 0	;存低位
				mov dx, 10h ;存高位,100h实在是太慢
delay_s0:		sub ax, 1
				sbb dx, 0 ;执行借位减，没有借位的时候直接减0，有的时候减去借位
				cmp ax, 0
				jne delay_s0
				cmp dx, 0
				jne delay_s0

				pop dx
				pop ax
				ret


;自己编写的9号中断
my_int9:		push ax
				push bx
				push es

				in al, 60h ;从60h端口中读取一个字节

				;调用BIOS的9号中断(读扫描码，扫描码和ascii放入BIOS键盘缓冲区，对键盘系统进行控制，比如向相关芯片发送应答信息)
				;必须调用原来的9号中断，原来的9号中断做了很多事情，具体见上面括号中的内容
				;必须调用原来的9号中断，不调不会有任何效果
				pushf ;标志寄存器入栈

				;修改标志寄存器的IF和TF位为0
				pushf
				pop bx
				and bx, 11111100b
				push bx
				popf

				mov bx, data
				mov ds, bx
				call dword ptr ds:[0] ;当前的cs和ip入栈，以及跳转到新的地方

				cmp al, 1 ;Esc的通码是1
				jne my_int9_exit
				mov bx, 0b800h
				mov es, bx
				inc byte ptr es:[12 * 160 + 40 * 2 + 1] ;把属性位加1，改变颜色

my_int9_exit:	pop es
				pop bx
				pop ax
				iret				

code ends

end start

